﻿using System;
using System.ServiceProcess;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using Neo4jRestSharp.Neo4jRestServices;
using Newtonsoft.Json.Linq;
using NUnit.Framework;

namespace Neo4jRestSharp.Test.Neo4jRestServices
{
    [TestFixture]
    public class NodeRestTests : BaseServicesTest
    {        
        private readonly Uri neo4jRestUri = new Uri("http://localhost:9999/");
        private const string ROOT_INDEX = "http://localhost:9999/index";
        private const string ROOT_NODE = "http://localhost:9999/node";
        private const string REFERENCE_NODE = "http://localhost:9999/node/0";        
        private int counter = 1;    
        
        [Test]
        public void GetRoodNode()
        {
            var restServices = new NodeRestServices(neo4jRestUri);
            
            //get root node
            string json = restServices.GetRootNode();
            
            //validate the return json with stored value
            Assert.AreEqual(Resource1.RootNodeJson, json);
            
            //parse and validate each item
            JObject jObject = JObject.Parse(json);
            Assert.AreEqual(jObject.Count, 3);
            
            JToken token;
            jObject.TryGetValue("index", out token);
            Assert.IsNotNull(token);            
            Assert.AreEqual(token.Value<string>(), ROOT_INDEX);
            
            jObject.TryGetValue("node", out token);
            Assert.IsNotNull(token);
            Assert.AreEqual(token.Value<string>(), ROOT_NODE);
            
            jObject.TryGetValue("reference node", out token);
            Assert.IsNotNull(token);
            Assert.AreEqual(token.Value<string>(), REFERENCE_NODE);          
        }

		[Test]
		public void CreateEmptyNode()
		{
			var restServices = new NodeRestServices(neo4jRestUri);
			
			//create node and get return json
			string json = restServices.CreateNode();
			//parse and validate each item
			JObject jObject = JObject.Parse(json);
			Assert.AreEqual(jObject.Count, 12);
			Assert.AreEqual(jObject["data"].Value<JToken>().Count(), 0);
		}

    	[Test]
        public void CreateNode()
        {
            var restServices = new NodeRestServices(neo4jRestUri);

            //create a person and get json string
			MatrixPerson morpheus = this.CreatePerson<MatrixPerson>(NODE1_NAME, NODE1_TITLE);
            morpheus.Title = NODE1_TITLE;
            morpheus.IsHuman = true;
            morpheus.IsAgent = false;
			JObject props = new JObject();
			foreach (var kvp in morpheus.GetProperties())
			{
				props.Add(kvp.Key, new JValue(kvp.Value));
			}

            //create node and get return json
			string json = restServices.CreateNode(props.ToString());
			JObject jObject = JObject.Parse(json);
    		string id = new Uri(jObject["self"].Value<string>()).Segments[2];

            //validate the return json with stored value
            string template = Resource1.MatrixPersonRedPillJson;
			template = template.Replace("/1", "/" + id);
            Assert.AreEqual(template, json);            
            
            //parse and validate each item            
            Assert.AreEqual(jObject.Count, 12);
            
            JToken token;
            jObject.TryGetValue("data", out token);
            Assert.IsNotNull(token);
            Assert.AreEqual(token.Count(), 4);
            Assert.AreEqual(token[MatrixPerson.NAME].Value<string>(), NODE1_NAME);
            Assert.AreEqual(token[MatrixPerson.TITLE].Value<string>(), NODE1_TITLE);
        }

        [Test]
        public void GetNode()
        {
            var restServices = new NodeRestServices(neo4jRestUri);
            //create a person 
            MatrixPerson morpheus = this.CreatePerson<MatrixPerson>(NODE1_NAME, NODE1_TITLE);
            //validate node against its stored properties
            ValidatePropertiesOnNode(morpheus);

            //get json string for person
            string json = restServices.GetNode(morpheus.Id);

            //validate the return json with stored value
            string template = Resource1.MatrixPersonRedPillJson;
            template = template.Replace("/1", "/" + morpheus.Id);
            Assert.AreEqual(template, json);

            //parse and validate each item
            JObject jObject = JObject.Parse(json);
            Assert.AreEqual(jObject.Count, 12);

            JToken token;
            jObject.TryGetValue("data", out token);
            Assert.IsNotNull(token);
            Assert.AreEqual(token.Count(), 4);
            Assert.AreEqual(token[MatrixPerson.NAME].Value<string>(), NODE1_NAME);
            Assert.AreEqual(token[MatrixPerson.TITLE].Value<string>(), NODE1_TITLE);
            Assert.AreEqual(token[MatrixPerson.ISHUMAN].Value<bool>(), morpheus.IsHuman);
            Assert.AreEqual(token[MatrixPerson.ISAGENT].Value<bool>(), morpheus.IsAgent);
        }

        [Test]
        public void SetNodeProperties()
        {
            var restServices = new NodeRestServices(neo4jRestUri);
            //create a person
            MatrixPerson morpheus = this.CreatePerson<MatrixPerson>(NODE1_NAME, NODE1_TITLE);
            //validate node against its stored properties
            ValidatePropertiesOnNode(morpheus);

            //change title and persist
            morpheus.Title = NODE1_TITLE_2;
            morpheus.IsAgent = true;
			JObject props = new JObject();
			foreach (var kvp in morpheus.GetProperties())
			{
				props.Add(kvp.Key, new JValue(kvp.Value));
			}
			restServices.SetNodeProperties(morpheus.Id, props.ToString());

            //get json string for person
            string json = restServices.GetNode(morpheus.Id);
            string template = Resource1.MatrixPersonBluePillJson;
            template = template.Replace("/1", "/" + morpheus.Id);
            Assert.AreEqual(template, json);

            //parse and validate each item
            JObject jObject = JObject.Parse(json);
            Assert.AreEqual(jObject.Count, 12);

            JToken token;
            jObject.TryGetValue("data", out token);
            Assert.IsNotNull(token);
            Assert.AreEqual(token.Count(), 4);
            Assert.AreEqual(token[MatrixPerson.NAME].Value<string>(), morpheus.Name);
            Assert.AreEqual(token[MatrixPerson.TITLE].Value<string>(), morpheus.Title);
            Assert.AreEqual(token[MatrixPerson.ISHUMAN].Value<bool>(), morpheus.IsHuman);
            Assert.AreEqual(token[MatrixPerson.ISAGENT].Value<bool>(), morpheus.IsAgent);
        }

        [Test]
        public void GetNodeProperties()
        {
            var restServices = new NodeRestServices(neo4jRestUri);
            //create node, then get node
            MatrixPerson morpheus = this.CreatePerson<MatrixPerson>(NODE1_NAME, NODE1_TITLE);
            //validate node against its stored properties
            ValidatePropertiesOnNode(morpheus);
        }

        [Test]
        public void RemoveNodePropertiesById()
        {
            var restServices = new NodeRestServices(neo4jRestUri);
            //create node, then get node
            MatrixPerson morpheus = this.CreatePerson<MatrixPerson>(NODE1_NAME, NODE1_TITLE);
            //validate node against its stored properties
            ValidatePropertiesOnNode(morpheus);

            //now clear properties and validate they are cleared
            restServices.RemoveNodeProperties(morpheus.Id);
            string json = restServices.GetNodeProperties(morpheus.Id);
            Assert.IsTrue(string.IsNullOrWhiteSpace(json));            
        }

        [Test]
        [Ignore]
        public void SetNodeProperty()
        {
            var restServices = new NodeRestServices(neo4jRestUri);
            //create node, then get node
            MatrixPerson morpheus = this.CreatePerson<MatrixPerson>(NODE1_NAME, NODE1_TITLE);
            //validate node against its stored properties
            ValidatePropertiesOnNode(morpheus);

            //now change a property
            restServices.SetNodeProperty(morpheus.Id, Person.TITLE, NODE1_TITLE_2);
            morpheus.Title = NODE1_TITLE_2;

            //get person and validate properties are correct
            string json = restServices.GetNodeProperties(morpheus.Id);
            string template = Resource1.MatrixPersonPropertiesWithBluePillJson;
            Assert.AreEqual(template, json);
            
            JObject jObject = JObject.Parse(json);
            Assert.AreEqual(jObject.Count, 4);
            Assert.AreEqual(jObject[MatrixPerson.NAME].Value<string>(), morpheus.Name);
            Assert.AreEqual(jObject[MatrixPerson.TITLE].Value<string>(), morpheus.Title);
            Assert.AreEqual(jObject[MatrixPerson.ISHUMAN].Value<bool>(), morpheus.IsHuman);
            Assert.AreEqual(jObject[MatrixPerson.ISAGENT].Value<bool>(), morpheus.IsAgent);
        }

        [Test]
        public void GetNodeProperty()
        {
            var restServices = new NodeRestServices(neo4jRestUri);
            //create node, then get node
            MatrixPerson morpheus = this.CreatePerson<MatrixPerson>(NODE1_NAME, NODE1_TITLE);
            //validate node against its stored properties
            ValidatePropertiesOnNode(morpheus);

            string name = restServices.GetNodeProperty(morpheus.Id, MatrixPerson.NAME);
            string title = restServices.GetNodeProperty(morpheus.Id, MatrixPerson.TITLE);
            Assert.AreEqual(name, morpheus.Name);
            Assert.AreEqual(title, morpheus.Title);
        }

        [Test]
        public void RemoveNodeProperty()
        {
            var restServices = new NodeRestServices(neo4jRestUri);
            //create node, then get node
            MatrixPerson morpheus = this.CreatePerson<MatrixPerson>(NODE1_NAME, NODE1_TITLE);
            //validate node against its stored properties
            ValidatePropertiesOnNode(morpheus);

            //remove node property
            restServices.RemoveNodeProperty(morpheus.Id, MatrixPerson.TITLE);

            //get node json
            string json = restServices.GetNodeProperties(morpheus.Id);

            //validate json against stored value
            string template = Resource1.MatrixPersonPropertiesNoTitleJson;
            Assert.AreEqual(template, json);

            //parse and validate each value
            JObject jObject = JObject.Parse(json);
            Assert.AreEqual(jObject.Count, 3);
            JToken jToken;
            Assert.IsFalse(jObject.TryGetValue(MatrixPerson.TITLE, out jToken));
            Assert.AreEqual(jObject[MatrixPerson.NAME].Value<string>(), morpheus.Name);
            Assert.AreEqual(jObject[MatrixPerson.ISHUMAN].Value<bool>(), morpheus.IsHuman);
            Assert.AreEqual(jObject[MatrixPerson.ISAGENT].Value<bool>(), morpheus.IsAgent);

            //remove node property
            restServices.RemoveNodeProperty(morpheus.Id, MatrixPerson.NAME);
            
            //get node json
            json = restServices.GetNodeProperties(morpheus.Id);

            //validate json against stored value
            template = Resource1.RemoveNodeNamePropertyNoTitleNameJson;
            Assert.AreEqual(template, json);

            //parse and validate each value
            jObject = JObject.Parse(json);
            Assert.AreEqual(jObject.Count, 2);
            jToken = null;
            Assert.IsFalse(jObject.TryGetValue(MatrixPerson.TITLE, out jToken));
            Assert.IsFalse(jObject.TryGetValue(MatrixPerson.NAME, out jToken));
            Assert.AreEqual(jObject[MatrixPerson.ISHUMAN].Value<bool>(), morpheus.IsHuman);
            Assert.AreEqual(jObject[MatrixPerson.ISAGENT].Value<bool>(), morpheus.IsAgent);          
        }

        [Test]
		[ExpectedException(typeof(Neo4jRestException))]
        public void RemoveNode()
        {
            var restServices = new NodeRestServices(neo4jRestUri);
            //create node, then get node
            MatrixPerson morpheus = this.CreatePerson<MatrixPerson>(NODE1_NAME, NODE1_TITLE);
            //validate node against its stored properties
            ValidatePropertiesOnNode(morpheus);

            //delete node
            restServices.DeleteNode(morpheus.Id);

			//Eat it, eat it, eat it, eat it...If it's gettin' cold, reheat it
            restServices.GetNode(morpheus.Id);
        }

        [Test]
        public void CreateRelationship()
        {
            var restServices = new NodeRestServices(neo4jRestUri);

            //create 2 nodes, then get both nodes
            MatrixPerson morpheus = this.CreatePerson<MatrixPerson>(NODE1_NAME, NODE1_TITLE);
            MatrixPerson neo = this.CreatePerson<MatrixPerson>(NODE2_NAME, NODE2_TITLE);

            //create link from morpheus to neo
            string json = "{\"to\": \"http://localhost:9999/node/" + neo.Id + "\", \"data\": { \"action\": \"Gave the red pill\" }, \"type\": \"Knows\"}";
            json = restServices.CreateRelationship(morpheus.Id, json);
        	JObject jObject = JObject.Parse(json);
        	Assert.AreEqual(jObject.Count, 7);
        	Assert.AreEqual(new Uri(jObject["start"].Value<string>()).Segments[2], morpheus.Id.ToString());
			Assert.AreEqual(new Uri(jObject["end"].Value<string>()).Segments[2], neo.Id.ToString());
        	Assert.AreEqual(jObject["type"].Value<string>(), "Knows");
        	Assert.AreEqual(jObject["data"].Value<JToken>()["action"].Value<string>(), "Gave the red pill");

            //create link from neo to morpheus
			json = "{\"to\": \"http://localhost:9999/node/" + morpheus.Id + "\", \"data\": { \"action\": \"Took the red pill\" }, \"type\": \"Knows\"}";
            json = restServices.CreateRelationship(neo.Id, json);
			jObject = JObject.Parse(json);
			Assert.AreEqual(jObject.Count, 7);
			Assert.AreEqual(new Uri(jObject["start"].Value<string>()).Segments[2], neo.Id.ToString());
			Assert.AreEqual(new Uri(jObject["end"].Value<string>()).Segments[2], morpheus.Id.ToString());
			Assert.AreEqual(jObject["type"].Value<string>(), "Knows");
			Assert.AreEqual(jObject["data"].Value<JToken>()["action"].Value<string>(), "Took the red pill");
        }

        [Test]		
        public void SetRelationshipProperties()
        {
			var restServices = new NodeRestServices(neo4jRestUri);

			//create 2 nodes, then get both nodes
			MatrixPerson morpheus = this.CreatePerson<MatrixPerson>(NODE1_NAME, NODE1_TITLE);
			MatrixPerson neo = this.CreatePerson<MatrixPerson>(NODE2_NAME, NODE2_TITLE);

			//create link from morpheus to neo
			string json = "{\"to\": \"http://localhost:9999/node/" + neo.Id + "\", \"type\": \"Knows\"}";
			json = restServices.CreateRelationship(morpheus.Id, json);
			JObject jObject = JObject.Parse(json);
			Assert.AreEqual(jObject.Count, 7);
			Assert.AreEqual(new Uri(jObject["start"].Value<string>()).Segments[2], morpheus.Id.ToString());
			Assert.AreEqual(new Uri(jObject["end"].Value<string>()).Segments[2], neo.Id.ToString());
			Assert.AreEqual(jObject["type"].Value<string>(), "Knows");
			Assert.AreEqual(jObject["data"].Value<JToken>().Count(), 0);
        	string MtoNid = new Uri(jObject["self"].Value<string>()).Segments[2];

			//create link from neo to morpheus
			json = "{\"to\": \"http://localhost:9999/node/" + morpheus.Id + "\", \"type\": \"Knows\"}";
			json = restServices.CreateRelationship(neo.Id, json);
			jObject = JObject.Parse(json);
			Assert.AreEqual(jObject.Count, 7);
			Assert.AreEqual(new Uri(jObject["start"].Value<string>()).Segments[2], neo.Id.ToString());
			Assert.AreEqual(new Uri(jObject["end"].Value<string>()).Segments[2], morpheus.Id.ToString());
			Assert.AreEqual(jObject["type"].Value<string>(), "Knows");
			Assert.AreEqual(jObject["data"].Value<JToken>().Count(), 0);
			string NtoMid = new Uri(jObject["self"].Value<string>()).Segments[2];

			//set and validate properties on relationship from M to N
			string propData = "{ \"action\": \"Gave the red pill\" }";
			restServices.SetRelationshipProperties(int.Parse(MtoNid), propData);
			json = restServices.GetRelationshipsOnNode(morpheus.Id, RelationshipDirection.Out, Enumerable.Empty<string>());
			JArray jArray = JArray.Parse(json);
			Assert.AreEqual(jArray.Count, 1);
			Assert.AreEqual(jArray[0]["data"].Value<JToken>()["action"].Value<string>(), "Gave the red pill");

			//set and validate properties on relationship from M to N
			propData = "{ \"action\": \"Took the red pill\" }";
			restServices.SetRelationshipProperties(int.Parse(NtoMid), propData);
			json = restServices.GetRelationshipsOnNode(neo.Id, RelationshipDirection.Out, Enumerable.Empty<string>());
			jArray = JArray.Parse(json);
			Assert.AreEqual(jArray.Count, 1);
			Assert.AreEqual(jArray[0]["data"].Value<JToken>()["action"].Value<string>(), "Took the red pill");
        }

        [Test]		
        public void GetRelationshipProperties()
        {
			var restServices = new NodeRestServices(neo4jRestUri);

			//create neo and morpheus, and all relationships
			int[] ids = Create2Nodes4Relationships();

			//validate props on morpheus
			string json = restServices.GetRelationshipsOnNode(ids[0], RelationshipDirection.Out, Enumerable.Empty<string>());
        	JArray jArray = JArray.Parse(json);
        	foreach (var rel in jArray)
        	{
        		json = restServices.GetRelationshipProperties(int.Parse(new Uri(rel["self"].Value<string>()).Segments[2]));
				if (!string.IsNullOrWhiteSpace(json))
				{
	        		JObject rel2 = JObject.Parse(json);
					Assert.AreEqual(rel["data"].Value<JToken>() ["action"].Value<string>(), rel2["action"].Value<string>());
				}
        	}

        	//validate props on neo
			json = restServices.GetRelationshipsOnNode(ids[1], RelationshipDirection.Out, Enumerable.Empty<string>());
			jArray = JArray.Parse(json);
			foreach (var rel in jArray)
			{
				json = restServices.GetRelationshipProperties(int.Parse(new Uri(rel["self"].Value<string>()).Segments[2]));
				if (!string.IsNullOrWhiteSpace(json))
				{
					JObject rel2 = JObject.Parse(json);
					Assert.AreEqual(rel["data"].Value<JToken>()["action"].Value<string>(), rel2["action"].Value<string>());
				}
			}
        }

        [Test]
        public void RemoveRelationshipProperties()
        {
			var restServices = new NodeRestServices(neo4jRestUri);

			//create neo and morpheus, and all relationships
			int[] ids = Create2Nodes4Relationships();						

			//validate props on morpheus
			string json = restServices.GetRelationshipsOnNode(ids[0], RelationshipDirection.Out, Enumerable.Empty<string>());
			JArray jArray = JArray.Parse(json);
			foreach (var rel in jArray)
			{
				//make sure we have props
				int relId = int.Parse(new Uri(rel["self"].Value<string>()).Segments[2]);
				json = restServices.GetRelationshipProperties(relId);
				if (!string.IsNullOrWhiteSpace(json))
				{
					JObject rel2 = JObject.Parse(json);
					Assert.AreEqual(rel["data"].Value<JToken>()["action"].Value<string>(), rel2["action"].Value<string>());
				}

				//remove props on relationships and validate
				restServices.RemoveRelationshipProperties(relId);
				json = restServices.GetRelationshipProperties(relId);
				Assert.IsTrue(string.IsNullOrWhiteSpace(json));				
			}

			//validate props on neo
			json = restServices.GetRelationshipsOnNode(ids[1], RelationshipDirection.Out, Enumerable.Empty<string>());
			jArray = JArray.Parse(json);
			foreach (var rel in jArray)
			{
				//mare sure we have props
				int relId = int.Parse(new Uri(rel["self"].Value<string>()).Segments[2]);
				json = restServices.GetRelationshipProperties(relId);
				if (!string.IsNullOrWhiteSpace(json))
				{
					JObject rel2 = JObject.Parse(json);
					Assert.AreEqual(rel["data"].Value<JToken>()["action"].Value<string>(), rel2["action"].Value<string>());
				}

				//remove props on relationships and validate
				restServices.RemoveRelationshipProperties(relId);
				json = restServices.GetRelationshipProperties(relId);
				Assert.IsTrue(string.IsNullOrWhiteSpace(json));	
			}
        }

        [Test]
		[Ignore]
        public void SetRelationshipProperty()
        {
            throw new NotImplementedException();
        }

        [Test]
		[Ignore]
        public void GetRelationshipProperty()
        {
            throw new NotImplementedException();
        }

		[Test]
		[Ignore]
        public void RemoveRelationshipProperty()
        {
            throw new NotImplementedException();
        }

        [Test]
        public void RemoveRelationship()
        {
            var restServices = new NodeRestServices(neo4jRestUri);

			//create neo and morpheus, and all relationships
			int[] ids = Create2Nodes4Relationships();

			//get all relationships for morhpeus
			var relTypes = Enums.Get<RelationshipType>();
			int startId = ids[0];
			string json = restServices.GetRelationshipsOnNode(startId, RelationshipDirection.All, relTypes.Select(e => e.ToString()));
			ValidateRelationshipJson(json, startId, ids, RelationshipDirection.All, relTypes);

			//now spin through and delete all relationships on morpheus
        	int count = 4;
        	string relId = null;
        	JArray jArray = JArray.Parse(json);
        	while (count > 0)
        	{
				Assert.AreEqual(jArray.Count, count--);

				//validate we just deleted the correct relationship id
				if (relId != null)
				{
					//make sure last relationship id is NOT in return list of ids
					foreach (JToken jToken in jArray)
					{
						Assert.AreNotEqual(relId, new Uri(jArray[0]["self"].Value<string>()).Segments[2]);
					}	
				}

				//delete the relationhsip
				relId = new Uri(jArray[0]["self"].Value<string>()).Segments[2];
        		restServices.RemoveRelationship(int.Parse(relId));

				//now go get all relationships for morpheus
				json = restServices.GetRelationshipsOnNode(startId, RelationshipDirection.All, relTypes.Select(e => e.ToString()));
				jArray = JArray.Parse(json);
        	}

			json = restServices.GetRelationshipsOnNode(startId, RelationshipDirection.All, relTypes.Select(e => e.ToString()));
			jArray = JArray.Parse(json);
			Assert.IsEmpty(jArray);
        }

        [Test]
        public void GetRelationshipsOnNode()
        {
            var restServices = new NodeRestServices(neo4jRestUri);

			//create neo and morpheus, and all relationships
        	int[] ids = Create2Nodes4Relationships();

            //TEST MATRIX (ha ha ha)            
            JObject jObject = null;
        	string json = null;
            //int[] startIds = new int[]{morpheus.Id, neo.Id};
            //test for each type of RelationshipDirection            
            foreach (var relDir in Enums.Get<RelationshipDirection>())
            {
				//Test for all relationship types via empty types enum
				//var relTypes = Enumerable.Empty<RelationshipType>();
				//foreach (int startId in ids)
				//{
				//    json = restServices.GetRelationshipsOnNode(startId, relDir, relTypes.Select(e => e.ToString()));
				//    ValidateRelationshipJson(json, startId, ids, relDir, relTypes);
				//}

                //Test for all relationship types
                var relTypes = Enums.Get<RelationshipType>();
                foreach (int startId in ids)
                {
                    json = restServices.GetRelationshipsOnNode(startId, relDir, relTypes.Select(e => e.ToString()));
					ValidateRelationshipJson(json, startId, ids, relDir, relTypes);
                }

                //Test for all relationship types Knows, Recruited
                relTypes = Enums.Get<RelationshipType>().Where(rt => rt == RelationshipType.Knows || rt == RelationshipType.Recruited);
				foreach (int startId in ids)
                {
                    json = restServices.GetRelationshipsOnNode(startId, relDir, relTypes.Select(e => e.ToString()));
					ValidateRelationshipJson(json, startId, ids, relDir, relTypes);
                }

                //Test for all relationship types Knows, WorksFor
                relTypes = Enums.Get<RelationshipType>().Where(rt => rt == RelationshipType.Knows || rt == RelationshipType.WorksFor);
				foreach (int startId in ids)
                {
                    json = restServices.GetRelationshipsOnNode(startId, relDir, relTypes.Select(e => e.ToString()));
					ValidateRelationshipJson(json, startId, ids, relDir, relTypes);
                }

                //Test for all relationship types Recruited, WorksFor
                relTypes = Enums.Get<RelationshipType>().Where(rt => rt == RelationshipType.Recruited || rt == RelationshipType.WorksFor);
				foreach (int startId in ids)
                {
                    json = restServices.GetRelationshipsOnNode(startId, relDir, relTypes.Select(e => e.ToString()));
					ValidateRelationshipJson(json, startId, ids, relDir, relTypes);
                }

                foreach (var relationshipType in Enums.Get<RelationshipType>())
                {
                    //Test single relationship type
					foreach (int startId in ids)
                    {
                        json = restServices.GetRelationshipsOnNode(startId, relDir, relTypes.Select(e => e.ToString()));
						ValidateRelationshipJson(json, startId, ids, relDir, relTypes);
                    }
                }
            }
        }

		private int[] Create2Nodes4Relationships()
		{
			var restServices = new NodeRestServices(neo4jRestUri);
			int[] startIds = new int[2];

			//create 2 nodes, then get both nodes
			MatrixPerson morpheus = this.CreatePerson<MatrixPerson>(NODE1_NAME, NODE1_TITLE);
			startIds[0] = morpheus.Id;
			MatrixPerson neo = this.CreatePerson<MatrixPerson>(NODE2_NAME, NODE2_TITLE);
			startIds[1] = neo.Id;

			//create link from morpheus to neo
			string json = "{\"to\": \"http://localhost:9999/node/" + neo.Id + "\", \"type\": \"Knows\"}";
			restServices.CreateRelationship(morpheus.Id, json);

			//create second link from morpheus to neo
			json = "{\"to\": \"http://localhost:9999/node/" + neo.Id + "\", \"data\": { \"action\": \"Gave the red pill\" }, \"type\": \"Recruited\"}";
			restServices.CreateRelationship(morpheus.Id, json);

			//create link from neo to morpheus
			json = "{\"to\": \"http://localhost:9999/node/" + morpheus.Id + "\", \"type\": \"Knows\"}";
			restServices.CreateRelationship(neo.Id, json);

			//create second link from neo to morpheus
			json = "{\"to\": \"http://localhost:9999/node/" + morpheus.Id + "\", \"data\": { \"action\": \"Took the red pill\" }, \"type\": \"WorksFor\"}";
			restServices.CreateRelationship(neo.Id, json);

			return startIds;
		}

        private void ValidateRelationshipJson(string json, int start, int[] ids, RelationshipDirection relDir, IEnumerable<RelationshipType> relTypes)
        {            
            Dictionary<string, string> testValues = new Dictionary<string, string>();

			foreach (RelationshipType relType in relTypes)
			{
				switch (relType)
				{
					case RelationshipType.Knows:
						if (relDir == RelationshipDirection.All
						    || (start == ids[0] && relDir == RelationshipDirection.Out)
						    || (start == ids[1] && relDir == RelationshipDirection.In))
						{							
							testValues.Add(string.Format("{0}|{1}|Knows", ids[0], ids[1]), "");
						}
						if (relDir == RelationshipDirection.All
						    || (start == ids[1] && relDir == RelationshipDirection.Out)
						    || (start == ids[0] && relDir == RelationshipDirection.In))
						{						
							testValues.Add(string.Format("{1}|{0}|Knows", ids[0], ids[1]), "");
						}
						break;
					case RelationshipType.Recruited:
						if (relDir == RelationshipDirection.All
						    || (start == ids[0] && relDir == RelationshipDirection.Out)
						    || (start == ids[1] && relDir == RelationshipDirection.In))
						{						
							testValues.Add(string.Format("{0}|{1}|Recruited", ids[0], ids[1]), "action|Gave the red pill");
						}
						break;
					case RelationshipType.WorksFor:
						if (relDir == RelationshipDirection.All
						    || (start == ids[1] && relDir == RelationshipDirection.Out)
						    || (start == ids[0] && relDir == RelationshipDirection.In))
						{						
							testValues.Add(string.Format("{1}|{0}|WorksFor", ids[0], ids[1]), "action|Took the red pill");
						}
						break;
				}
			}

        	JArray jArray = JArray.Parse(json);
            Assert.AreEqual(jArray.Count, testValues.Count);
            foreach (JToken token in jArray)
            {
                string startId = new Uri(token["start"].Value<string>()).Segments[2];
                string endId = new Uri(token["end"].Value<string>()).Segments[2];
                string action = token["type"].Value<string>();
                string key = startId + "|" + endId + "|" + action;
                string[] testData = testValues[key].Split('|');
                JToken dataToken = token["data"].Value<JToken>();
                if (testData.Length == 1 && string.IsNullOrWhiteSpace(testData[0]))
                {
                    Assert.IsNull(dataToken.First);
                }
                else
                {
                    Assert.AreEqual(dataToken[testData[0]].Value<string>(), testData[1]);
                }
            }
        }




        private void ValidatePropertiesOnNode(Person person)
        {
            var restServices = new NodeRestServices(neo4jRestUri);

            //get person properties by id and validate properties against source object
            string json = restServices.GetNodeProperties(person.Id);
            string template = Resource1.MatrixPersonPropertiesJson;
            Assert.AreEqual(template, json);
            JObject jObject = JObject.Parse(json);
            
            MatrixPerson mp = person as MatrixPerson;
            if (mp == null)
            {
                Assert.AreEqual(jObject.Count, 2);
                Assert.AreEqual(jObject[MatrixPerson.NAME].Value<string>(), person.Name);
                Assert.AreEqual(jObject[MatrixPerson.TITLE].Value<string>(), person.Title);
            }
            else
            {
                Assert.AreEqual(jObject.Count, 4);
                Assert.AreEqual(jObject[MatrixPerson.NAME].Value<string>(), mp.Name);
                Assert.AreEqual(jObject[MatrixPerson.TITLE].Value<string>(), mp.Title);
                Assert.AreEqual(jObject[MatrixPerson.ISHUMAN].Value<bool>(), mp.IsHuman);
                Assert.AreEqual(jObject[MatrixPerson.ISAGENT].Value<bool>(), mp.IsAgent);    
            }            
        }        
    } 
}
